#include <cctype>
#include <sstream>
#include <algorithm>
#include <functional>
#include "icache/file_sequence.h"
#include "mswin/file_dir.h"

namespace icache {

inline void toupper(string & s)
{
	string::iterator i;
	for (i = s.begin(); i != s.end(); ++i)
		*i = std::toupper(*i);
}

struct is_not_digit : std::unary_function<char, bool> {
	bool operator () (char c) const
		{ return !std::isdigit(c); }
};

void file_sequence::set_basepath(string const & subpath)
{
	_basepath = mswin::parent(subpath);
	if (_basepath.empty()) {
		_basepath = mswin::getcwd(); //examples: "c:\code", "c:\"
		if (_basepath.size() > 3)
			_basepath += '\\';
	}
}

void file_sequence::create_by_example(const string & filename)
{
	string filter = filename;
	string::reverse_iterator i;
	bool was_digits = false;
	for (i = filter.rbegin(); i != filter.rend(); ++i) {
		if (*i == '\\' || *i == '/')
			break;
		if (isdigit(*i)) {
			*i = '?';
			was_digits = true;
		}
		else if (was_digits)
			break;
	}
	if (was_digits)
		create_by_filter(filter);
	else {
		set_basepath(filename);
		_framepaths.resize(1);
		_framepaths[0] = mswin::child(filename);
		_filter = _basepath + _framepaths[0];
		_first_frame_num = 0;
	}
}

void file_sequence::create_by_filter(const string & filter)
{
	set_basepath(filter);

	_filter = filter;
	mswin::enum_file find(_filter);
	for (; !find.end(); ++find) {
		_framepaths.push_back(find.name());
		toupper(_framepaths.back());
	}
	std::sort(_framepaths.begin(), _framepaths.end());

	if (_framepaths.empty())
		throw exception(std::string("bad filter: ") + _filter);

	string name = mswin::basename(_framepaths[0]);
	string number(std::find_if(name.rbegin(), name.rend(), is_not_digit()).base(), name.end());

	std::istringstream in(number);
	in >> _first_frame_num;
	if (in.fail())
		_first_frame_num = 0;
}

void file_sequence::clear()
{
	_filter.clear();
	_basepath.clear();
	_framepaths.clear();
}

} //namespace icache
